// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/log.h>

void usage(void) {
  fprintf(stderr,
          "usage: dlog        dump the zircon debug log\n"
          "\n"
          "options: -f        don't exit, keep waiting for new messages\n"
          "         -p <pid>  only show messages from specified pid\n"
          "         -t        only show the text of messages (no metadata)\n"
          "         -h        show help\n");
}

int main(int argc, char** argv) {
  bool tail = false;
  bool filter_pid = false;
  bool plain = false;
  zx_koid_t pid = 0;
  zx_handle_t h;

  while (argc > 1) {
    if (!strcmp(argv[1], "-h")) {
      usage();
      return 0;
    } else if (!strcmp(argv[1], "-f")) {
      tail = true;
    } else if (!strcmp(argv[1], "-t")) {
      plain = true;
    } else if (!strcmp(argv[1], "-p")) {
      argc--;
      argv++;
      if (argc < 2) {
        usage();
        return -1;
      }
      errno = 0;
      pid = strtoull(argv[1], NULL, 0);
      if (errno) {
        fprintf(stderr, "dlog: invalid pid\n");
        return -1;
      }
      filter_pid = true;
    } else {
      usage();
      return -1;
    }
    argc--;
    argv++;
  }

  if (zx_debuglog_create(ZX_HANDLE_INVALID, ZX_LOG_FLAG_READABLE, &h) < 0) {
    fprintf(stderr, "dlog: cannot open debug log\n");
    return -1;
  }

  char buf[ZX_LOG_RECORD_MAX];
  zx_log_record_t* rec = (zx_log_record_t*)buf;
  for (;;) {
    zx_status_t status;
    if ((status = zx_debuglog_read(h, 0, rec, ZX_LOG_RECORD_MAX)) < 0) {
      if ((status == ZX_ERR_SHOULD_WAIT) && tail) {
        zx_object_wait_one(h, ZX_LOG_READABLE, ZX_TIME_INFINITE, NULL);
        continue;
      }
      break;
    }
    if (filter_pid && (pid != rec->pid)) {
      continue;
    }
    if (!plain) {
      char tmp[32];
      size_t len = snprintf(tmp, sizeof(tmp), "[%05d.%03d] ", (int)(rec->timestamp / 1000000000ULL),
                            (int)((rec->timestamp / 1000000ULL) % 1000ULL));
      write(1, tmp, (len > sizeof(tmp) ? sizeof(tmp) : len));
    }
    write(1, rec->data, rec->datalen);
    if ((rec->datalen == 0) || (rec->data[rec->datalen - 1] != '\n')) {
      write(1, "\n", 1);
    }
  }
  return 0;
}
